package jers.util;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import jers.JERS;

/**
 * Classe de utilitarios gerais do sistema. 
 */
public final class Utility {
	
	/**
	 * Proibido a instanciacao.
	 */
	private Utility() {
		super();
	}

	/**
	 * Obtem um codigo long unico para qualquer instancia ou thread do sistema.
	 * 
	 * @return
	 * 		O codigo unico gerado.
	 */
	public synchronized static long getCode() {
		try {
			Thread.sleep(1);
		} catch (InterruptedException e) {
			JERS.log.error("The thread ", Thread.currentThread().getName(), 
					" can not wait to sync. Error: ", e.getMessage());
		}
		return System.currentTimeMillis(); 
	}
	
	/**
	 * Retorna uma representacao {@link String} do objeto.
	 * <p>
	 * <b>Formato:</b><br>
	 * 		<code>ClassName{attributeA:valueA,...,attributeN:valueN}</code>
	 * </p>
	 * @param 
	 * 		object - O objeto a ser representado em string.
	 * @return 
	 * 		A representacao {@link String} do objeto.
	 */
	public static String toString(Object object) {
		StringBuilder sb;
		try {
			sb = new StringBuilder();
			sb.append(object.getClass().getSimpleName()).append("{");
			
			for (Field field : object.getClass().getDeclaredFields()) {
				field.setAccessible(true);
				sb.append(field.getName());
				sb.append(":");
				sb.append(field.get(object));
				sb.append(",");
			}
			sb.setLength(sb.length() -1);
			sb.append("}");
		} catch (Exception e) {
			sb = new StringBuilder(object.toString()); 
		}
		return sb.toString();
	}

	/**
	 * Concatena as {@link Object} passadas usando um {@link StringBuilder}.
	 * 
	 * @param 
	 * 		objects - Os objetos a serem concatenadas.
	 * @return 
	 * 		A string resultante.
	 */
	public static String concat(Object... objects) {
		StringBuilder sb = new StringBuilder();
		for (Object string : objects) {
			sb.append(string);
		}
		return sb.toString();
	}
	
	/**
	 * Valida os {@link Object} passados checando se nao sao nulos.
	 * 
	 * @param 
	 * 		objs - Os {@link Object} a serem validados. 
	 * @return
	 * 		Verdadeiro quando nenhum {@link Object} for nulo.
	 */
	public static boolean validate(Object... objs) {
		if (objs != null && objs.length > 0) {
			for (Object p : objs) {
				if (p == null) {
					return false;
					
				} else if (p instanceof String) {
					String s = (String) p; 
					return validate(s);
					
				} else if (p instanceof Collection<?>) {
					Collection<?> collection = (Collection<?>) p;
					return !collection.isEmpty();
				}
			}
			return true;
		}
		return false;
	}
	
	/**
	 * Valida as {@link String} passadas checando se nao sao nulas ou vazias.
	 * 
	 * @param 
	 * 		strs - As {@link String} a serem validadas.
	 * @return
	 * 		Verdadeiro quando nenhuma {@link String} for nula ou vazia.
	 */
	public static boolean validate(String... strs) {
		if (strs != null && strs.length > 0) {
			for (String p : strs) {
				if (p == null || "".equals(p.trim())) {
					return false;
				}
			}
			return true;
		}
		return false;
	}
	
	/**
	 * Preenche uma {@link String} com o caracter e quantidade passados.
	 * 
	 * @param character O caracter a ser preenchido.
	 * @param quantity A quantidade do caracter.
	 * @return A string resultante.
	 */
	public static String fill(char character, int quantity) {
		StringBuilder sb = new StringBuilder(quantity);
		for (int i = 0; i < quantity; ++i) {
			sb.append(character);
		}
		return sb.toString();
	}

	/**
	 * Converte uma {@link String} no formato CSV para uma {@link List}
	 * <p>
	 * Separadores validos: 
	 * <br> - virgula ',' 
	 * <br> - ponto e virgula ';' 
	 * <br> - pipe '|' 
	 * </p>
	 *   
	 * @param csv A string no formato CSV.
	 * @return A lista de Strings.
	 */
	public static List<String> fromCSV(String csv) {
		List<String> list = new LinkedList<String>();
		
		if (validate(csv)) {
			String[] tokens = csv.split("\\s*[,;|]\\s*");
			if (tokens != null && tokens.length > 0) {
				list.addAll(Arrays.asList(tokens));
			}
		}
		return list;
	}
	
	/**
	 * Converte uma {@link List} para uma {@link String} no formato CSV.
	 * <p> 
	 * Separador usado: 
	 * <br> - virgula ',' 
	 * </p>
	 *   
	 * @param csv A string no formato CSV.
	 * @return A lista de Strings.
	 */
	public static String toCSV(List<String> csv) {
		StringBuilder sb = new StringBuilder();
		
		if (csv != null && !csv.isEmpty()) {
			for (String s : csv) {
				sb.append(s).append(",");
			}
			sb.setLength(sb.length() -1);
		}
		return sb.toString();
	}

	/**
	 * Converte uma lista de caminhos de arquivos para ponteiros de arquivos.
	 * 
	 * @param filePaths Lista de caminhos em {@link String}.
	 * @return Lista de ponteiros de arquivos {@link File}.
	 * @throws IOException 
	 */
	public static File[] toFiles(String... filePaths) throws IOException {
		File[] files = null;
		if (filePaths != null) {
			files = new File[filePaths.length];
			for (int i = 0; i < filePaths.length; ++i) {
				files[i] = new File(filePaths[i]).getCanonicalFile();
			}
		}
		return files;
	}
	
}
